/*
    JSPWiki - a JSP-based WikiWiki clone.
    Licensed to the Apache Software Foundation (ASF) under one
    or more contributor license agreements.  See the NOTICE file
    distributed with this work for additional information
    regarding copyright ownership.  The ASF licenses this file
    to you under the Apache License, Version 2.0 (the
    "License"); fyou may not use this file except in compliance
    with the License.  You may obtain a copy of the License at
       http://www.apache.org/licenses/LICENSE-2.0
    Unless required by applicable law or agreed to in writing,
    software distributed under the License is distributed on an
    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    KIND, either express or implied.  See the License for the
    specific language governing permissions and limitations
    under the License.
*/
/*eslint-env browser*/
/*global $, Class, Events, Snipe  */
/*
Class: SnipEditor.Sections
    This dialog displays the list of page sections.

    (all) - allows to select all sections (auto generated)
    start-of-page - only present when first section starts on an offset > 0
    section1..n - section titles, with indentation level depending on their weight

    The set of sections is generated by the parseSections() callback handler.
    This parser returns an array of section "descriptors":
>    [ {title:text, start:char-offset, indent:indentation-level}, ... ]

    Clicking an entry triggers the updateSections() callback handler.
    FIXME: why not fire an onAction event (similar to other dialogs)

Depends:
    Snipe

Example:
(start code)
    div.cage
      div.btn.btn-link
        span.icon-bookmark
            span.caret
      ul.dropdown-menu [data-sections="div"][data-hover-parent=".cage"]
        li  a first
        li  a ..
        li  a.dropdown-divider
        li  a ..


    new Snipe.Sections( sectionDropDown, {
        snipe: snipe,
        parser: function(text){ .. return [[{title, start, depth}],..]; }
    });
(end)
*/

Snipe.Sections = new Class({

    Implements: [Events],
    Binds: ["show","update","action"],

    options: {
        //snipe: snip-editor
        //parser: function(text){ returns [[title,start,depth]..] }
        all: "( all )".localize(),
        startOfPage: "Start of Page".localize()
    },

    initialize: function(element, options){

        var self = this,
            snipe = options.snipe;

        self.container = element;
        self.parser = options.parser;

        self.list = element.getElement("ul").addEvent("click:relay(a)", self.action);

        self.main = snipe.get("mainarea");
        self.work = $( snipe.get("textarea") );

        snipe.addEvent( "change", self.update.debounce(500) );

        self.parse();
        self.action( location.search );  //url?section=0..n
        self.show();

    },

    /*
    Function: parse
        Invoke the external parser on the contents of the main textarea.
        This external parser should return an array with an entry for each section:
        [ {title:text, start:char-offset, depth:nesting level}, ... ]

        >        0 : start-of-page (if applicable) => title=s-1 => cursor=-1
        >        1..n : page sections              => title=s0..sn => cursor=0..n
    */
    parse: function(){

        this.sections = this.parser( this.main.value );

    },

    /*
    Function: show
        UPDATE/RFEFRESH the section dropdown-menu.
        Highlight the current item.

    (start code)
        ul.dropdown-menu
            li
                a.indent-0.section-2 (all)
            li
                a.indent-0.section-1 Start Of Page
            li.divider
            li
                a.indent-0.section0 Title-Section-0
            li
                a.indent-0.section1 Title-Section-1
            ...
            li
                a.indent-0.section99 Title-Section-2
    (end)
    */
    show: function( ){

        //console.log("Sections show",this.current, this.sections.length, this.sections[3]);

        var data = [],
            options = this.options,
            current = this.current,
            sections = this.sections,

            addItem = function(indent,name,offset){

                data.push("li" + (offset==current ? ".active" : ""),[
                    "a.indent-" + indent + ".section" + offset, { html:name }
                ]);

            };

        addItem(0, options.all ,-2);

        if( sections[0] ){

            if( sections[0].start > 0 ){ addItem(0, options.startOfPage, -1); }

            data.push( "li.divider" );

            sections.each( function(item, idx){

                addItem( item.depth, item.title/*.trunc(36)*/, idx );

            });

        }

        this.list.empty().adopt( data.slick() );

    },

    /*
    Function: update
        Make sure that changes to the work textarea are propagated to the main textarea.
        This function handles the propagation of changes into the main textarea.
    */
    update: function(){

        //console.log("****Snipe.Sections : change main");

        var self = this,
            main = self.main,
            work = self.work.value,
            s = main.value;

        //insert \n to ensure the next section always starts on a new line.
        if( work.slice(-1) != "\n" ){ work +="\n"; }

        //console.log("change txta: from="+self.begin+ " end="+self.end);
        main.value = s.slice(0, self.begin) + work  + s.slice(self.end);

        self.end = self.begin + work.length;

        self.parse();
        self.show();

    },

    /*
    Function: action
        This function copies the selected section from the main to the work textarea.
        It is invoked at initialization and through the dialog onAction click handler.

    Arguments:
        item - index of selected section: all, -1, 0..n
    */
    action:function( item ){

        //console.log("Sections: action",item);
        var self = this,
            main = self.main.value,
            work = self.work,
            sections = self.sections,
            begin = 0,
            end = main.length;

        if( item ){

            //item.target => event.target; this is an onclick invocation
            if( item.target ){ item = item.target.className; }

            //section-2=All, section-1=StartOfPage, section0..section99=rest
            item = ( item.match( /section=?(-?\d+)/ )||[,-2])[1].toInt();


            if( item == -1 ){

                //show the Start Of Page, prior to the first real section
                end = sections[0].start;

            } else if(item >= 0  && sections[item] ){

                begin = sections[item].start;
                if( sections[item+1] ){ end = sections[item+1].start; }

            }

            self.current = item;

        }

        //work.value = "";  //FIXME google chrome  43.0.2357.65 bug -- if omitted, the textarea is displayed EMPTY!! ??
        work.value = main.slice(begin, end);
        work.setSelectionRange(0,0); //why not go via Textarea()..., for better bw compat. :FVK:
        self.begin = begin;
        self.end = end;

        //section-selected class : turn bookmark icon red or blue
        self.container.ifClass( item >= -1, "section-selected");

        //update the dropdown menu, and highlight the current item
        self.show();

        work.fireEvent("change");  //needed to rerun page preview

        return false; //stop click event propagation

    }

});